package base.reflection_demo.demo_xx;

import javassist.*;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

/** TODO 暂未了解
 * Java字节码操作
 * Java动态性的两种常见实现方式: 反射 和 字节码操作
 * 运行时操作字节码
 * 优势:
 * 比反射开销小,性能高;
 * JAVAssist库性能高于反射,小于ASM;
 * CGLib库跟JAVAssist差不多,但后者使用简单,因此常采用JAVAssist库
 *
 * JAVAssist库的简单使用: 创建一个新类Emp,创建的是字节码文件class - Emp.class
 * 有点问题:后面用到再学习吧
 * package com.sann.bean;
 *
 * public class Emp {
 *     private int empno = this.empno;
 *     private String ename = this.ename;
 *
 *     public Emp(int i, String str) {
 *     }
 *
 *     public String getEname() {
 *         return this.ename;
 *     }
 *
 *     public void setEname(String str) {
 *         this.ename = str;
 *     }
 * }
 */
@Slf4j
public class ByteCodeOperation {

    // 动态创建Emp.class,之后用反编译工具jadx-gui 进行查看这个class
    public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException {
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.makeClass("com.sann.bean.Emp");

        // 创建属性
        CtField private_string_ename = CtField.make("private String ename;", ctClass);
        CtField private_int_empno = CtField.make("private int empno;", ctClass);
        ctClass.addField(private_string_ename);
        ctClass.addField(private_int_empno);

        // 创建方法
        CtMethod setEname = CtMethod.make("public void setEname(String ename){this.ename=ename;}", ctClass);
        CtMethod getEname = CtMethod.make("public String getEname(){return this.ename;}", ctClass);
        ctClass.addMethod(setEname);
        ctClass.addMethod(getEname);

        // 添加构造方法
        CtConstructor cc = new CtConstructor(new CtClass[]{CtClass.intType, pool.get("java.lang.String")}, ctClass);
        cc.setBody("{this.empno=empno; this.ename=ename;}");
        ctClass.addConstructor(cc);

        ctClass.writeFile("d:/myjava");// 将上面构造好的类写入到文件目录
        log.info("生成类成功");
    }

}
